/*************************************************************************
@Author: bighu
@Created Time : 2022年02月23日 星期三 13时28分59秒
@File Name: ring.go
@Description:
************************************************************************/
package main

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	mrand "math/rand"
	"os"
	"strconv"
	"time"
)

//变量
var (
	//公钥链表
	listPubKey = []rsa.PublicKey{}
	//签名者私钥
	userPrivKey rsa.PrivateKey
	//签名者的公钥
	userPubKey rsa.PublicKey
	//随机签名者
	user  int
	listv = [][]byte{}
)

func main() {
	//产生密钥
	MakeRsaKeyList()
	flMD5 := funGetFileMD5("test.docx")
	fmt.Println(flMD5)
	n, err := strconv.ParseUint(flMD5[64:], 16, 64)
	if err != nil {
		panic(err)
	}
	listR, v := funSign(n)
	if funVerify(n, listR, listPubKey, v) {
		fmt.Println("成功")
	} else {
		fmt.Println("失败")
	}

}

//计算一个文件的MD5
func funGetFileMD5(flPath string) string {
	//截取path
	path := fmt.Sprintf("./%s", flPath)
	pFile, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	//处理完成之后关闭文件
	defer pFile.Close()
	fileMD5 := md5.New()
	io.Copy(fileMD5, pFile)
	return hex.EncodeToString(fileMD5.Sum(nil))
}

//密钥产生函数
func MakeRsaKeyList() {
	//随机选取一个人的序号，将其当做签名者
	mrand.Seed(time.Now().UnixNano())
	user := mrand.Intn(10)
	//产生10组密钥，其中9组只保留公钥,另外一组当组签名者的公私钥对
	for i := 0; i < 10; i++ {
		Key, err := rsa.GenerateKey(rand.Reader, 1024)
		if err != nil {
			panic(err)
		}
		//保留签名者的私钥
		if i == user {
			userPrivKey = *Key
			userPubKey = Key.PublicKey
		} else {
			listPubKey = append(listPubKey, Key.PublicKey)
		}
	}
}

//产生随机字符串
func funRandStr(length int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := []byte{}
	mrand.Seed(time.Now().UnixNano() + int64(mrand.Intn(100)))
	for i := 0; i < length; i++ {
		result = append(result, bytes[mrand.Intn(len(bytes))])
	}
	return string(result)
}

//选取两数中的最小值
func funMin(a int, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}

//选取两数中的最大值
func funMax(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

//byte亦或算法
func funByteXor(Lbyte []byte, Rbyte []byte) []byte {
	result := []byte{}
	for i := 0; i < len(Rbyte); i++ {
		result = append(result, Lbyte[i]^Rbyte[i])
	}
	for i := len(Rbyte); i < len(Lbyte); i++ {
		result = append(result, Lbyte[i])
	}
	return result
}

//签名算法
func funSign(flMD5 uint64) ([][]byte, []byte) {
	//随机数链表
	var listR = []int64{}
	//产生n-i个随机数
	for i := 0; i < 9; i++ {
		mrand.Seed(time.Now().UnixNano())
		listR = append(listR, mrand.Int63n(2^64))
	}
	//产生第一个v
	listv = append(listv, []byte(funRandStr(128)))
	for i := 0; i < 9; i++ {
		vi := listR[i] ^ listPubKey[i].E%listPubKey[i].N
		if err != nil {
			fmt.Println(&listPubKey[i])
			panic(err)
		}
		//依次计算其他的v
		listv = append(listv, funByteXor(funByteXor(listv[len(listv)-1], vi), []byte(flMD5)))
	}
	//计算初用户需要产生的Y,由于用户拥有自己的公钥，所以用户可以计算出那个“随机”的X
	userY := funByteXor(funByteXor(listv[0], listv[len(listv)-1]), []byte(flMD5))
	fmt.Println(userY)
	userR, err := rsa.DecryptOAEP(nil, rand.Reader, &userPrivKey, userY, []byte("orders"))
	if err != nil {
		fmt.Println(userR)
		panic(err)
	}
	listR = append(listR, userR)
	listPubKey = append(listPubKey, userPubKey)
	mrand.Seed(time.Now().UnixNano())
	move := mrand.Intn(10)
	//对环进行移位
	v := listv[move]
	listR = append(listR[move:], listR[:move]...)
	listPubKey = append(listPubKey[move:], listPubKey[:move]...)
	return listR, v
}

//验证是否成环
func funVerify(flMD5 string, R [][]byte, pKey []rsa.PublicKey, v []byte) bool {
	ansv := v
	for i := 0; i < len(pKey); i++ {
		m, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &pKey[i], []byte(R[i]), nil)
		if err != nil {
			panic(err)
		}
		v = funByteXor(funByteXor(v, m), []byte(flMD5))
	}
	if string(ansv) == string(v) {
		return true
	} else {
		return false
	}
}
